#include "adc_multi_channel_dma.h"
#include <stdio.h>
#include <stdint.h>
#include <math.h>

uint16_t temp_table[] = {
    58354, // -55
    55464, // -54
    52698, // -53
    50048, // -52
    47515, // -51
    45097, // -50
    42789, // -49
    40589, // -48
    38492, // -47
    36496, // -46
    34597, // -45
    32791, // -44
    31075, // -43
    29444, // -42
    27896, // -41
    26427, // -40
    25034, // -39
    23713, // -38
    22460, // -37
    21273, // -36
    20148, // -35
    19083, // -34
    18075, // -33
    17120, // -32
    16216, // -31
    15361, // -30
    14551, // -29
    13785, // -28
    13061, // -27
    12376, // -26
    11728, // -25
    11114, // -24
    10535, // -23
    9986,  // -22
    9468,  // -21
    8977,  // -20
    8513,  // -19
    8075,  // -18
    7660,  // -17
    7267,  // -16
    6896,  // -15
    6545,  // -14
    6212,  // -13
    5898,  // -12
    5601,  // -11
    5319,  // -10
    5053,  // -9
    4801,  // -8
    4562,  // -7
    4336,  // -6
    4122,  // -5
    3920,  // -4
    3728,  // -3
    3546,  // -2
    3374,  // -1
    3211,  // 0
    3057,  // 1
    2910,  // 2
    2771,  // 3
    2639,  // 4
    2515,  // 5
    2396,  // 6
    2284,  // 7
    2177,  // 8
    2076,  // 9
    1978,  // 10
    1889,  // 11
    1802,  // 12
    1720,  // 13
    1642,  // 14
    1568,  // 15
    1497,  // 16
    1430,  // 17
    1366,  // 18
    1306,  // 19
    1248,  // 20
    1193,  // 21
    1141,  // 22
    1092,  // 23
    1044,  // 24
    1000,  // 25
    957,   // 26
    916,   // 27
    877,   // 28
    840,   // 29
    805,   // 30
    771,   // 31
    739,   // 32
    709,   // 33
    679,   // 34
    652,   // 35
    625,   // 36
    600,   // 37
    576,   // 38
    552,   // 39
    530,   // 40
    509,   // 41
    489,   // 42
    470,   // 43
    452,   // 44
    434,   // 45
    417,   // 46
    401,   // 47
    386,   // 48
    371,   // 49
    358,   // 50
    344,   // 51
    331,   // 52
    318,   // 53
    306,   // 54
    295,   // 55
    284,   // 56
    274,   // 57
    264,   // 58
    254,   // 59
    245,   // 60
    236,   // 61
    228,   // 62
    220,   // 63
    212,   // 64
    205,   // 65
    198,   // 66
    191,   // 67
    184,   // 68
    178,   // 69
    172,   // 70
    166,   // 71
    160,   // 72
    155,   // 73
    150,   // 74
    145,   // 75
    140,   // 76
    135,   // 77
    131,   // 78
    126,   // 79
    122,   // 80
    118,   // 81
    115,   // 82
    111,   // 83
    107,   // 84
    104,   // 85
    101,   // 86
    97,    // 87
    94,    // 88
    91,    // 89
    89,    // 90
    86,    // 91
    83,    // 92
    81,    // 93
    78,    // 94
    76,    // 95
    74,    // 96
    71,    // 97
    69,    // 98
    67,    // 99
    65,    // 100
    63,    // 101
    61,    // 102
    60,    // 103
    58,    // 104
    56,    // 105
    55,    // 106
    53,    // 107
    52,    // 108
    50,    // 109
    49,    // 110
    47,    // 111
    46,    // 112
    45,    // 113
    43,    // 114
    42,    // 115
    41,    // 116
    40,    // 117
    39,    // 118
    38,    // 119
    37,    // 120
    36,    // 121
    35,    // 122
    34,    // 123
    33,    // 124
    32,    // 125
};

/**
 * 热敏电阻
 */
void adc0_config(void)
{
    // 1. 引脚配置,
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOC);

    // gpio模式: 模拟输入,直接与外部相连
    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1);
    gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_4);

    // 2. adc初始化
    // 2.1 adc时钟
    rcu_periph_clock_enable(RCU_ADC0);
    adc_deinit();

    // 2.2 ADC 4分频
    adc_clock_config(ADC_ADCCK_PCLK2_DIV4);

    // 2.3 配置ADC采样精度与对齐
    adc_resolution_config(ADC0, ADC_RESOLUTION_12B); // 12位精度

    adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT); // 右对齐
    // 打开内部温度通道
    adc_channel_16_to_18(ADC_TEMP_VREF_CHANNEL_SWITCH, ENABLE);

    // 2.4 配置通道,通道长度3,通道内容PA1,PC4,内部温度
    adc_channel_length_config(ADC0, ADC_ROUTINE_CHANNEL, 3);

    // 2.5 配置具体通道
    adc_routine_channel_config(ADC0, 0, ADC_CHANNEL_1, ADC_SAMPLETIME_15);
    adc_routine_channel_config(ADC0, 1, ADC_CHANNEL_4, ADC_SAMPLETIME_15);
    adc_routine_channel_config(ADC0, 2, ADC_CHANNEL_16, ADC_SAMPLETIME_15);

    // 2.6 ADC DMA开启
    // 当eoc为1,则进行dma传输,传输后eoc自动归0
    adc_dma_request_after_last_enable(ADC0);
    // 开启adc的dma支持
    adc_dma_mode_enable(ADC0);

    // 2.7 开启连续与扫描模式
    adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);       // 开启多通道扫描
    adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE); // 开启连续测量

    // 2.8 开启adc自校验
    adc_enable(ADC0);
    adc_calibration_enable(ADC0);

    // 2.9 因为开启了连续测量,仅触发adc一次即可
    adc_software_trigger_enable(ADC0, ADC_ROUTINE_CHANNEL);
}

uint16_t adc_arr[3]; // 3个通道
void adc0_dma_config(void)
{
    // 1. rcu时钟
    rcu_periph_clock_enable(RCU_DMA1); // dma1_ch0_subperiph0
    // 2. dma重置
    dma_deinit(DMA1, DMA_CH0);

    // 3. 结构体

    dma_single_data_parameter_struct dma_init_struct;
    dma_single_data_para_struct_init(&dma_init_struct);

    // 4. 配置dma传输参数
    // 方向:外设到内存
    dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;

    // 5.1 配置内存地址(目的地)

    dma_init_struct.memory0_addr = (uint32_t)adc_arr;
    // 5.2 设置内存增长,(必须开启,如不开,结果固定为arr[0])
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;

    // 6.1 设置外设地址
    dma_init_struct.periph_addr = (uint32_t)(&ADC_RDATA(ADC0));

    // 6.2 设置外设增长:关闭,仅有一个寄存器
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;

    // 7.1 设置传输长度
    // 16位:读的寄存器是16位
    // dma_init_struct.periph_memory_width = DMA_MEMORY_WIDTH_16BIT;//使用外设宽度
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_16BIT;
    //
    dma_init_struct.number = 3; // 3个通道

    // 8.优先级
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    // 9.初始化dma
    dma_single_data_mode_init(DMA1, DMA_CH0, &dma_init_struct);

    // 10 子外设

    dma_channel_subperipheral_select(DMA1, DMA_CH0, DMA_SUBPERI0);

    //  11.dma循环(dma的ftf功能自动控制)
    // 循环模式不需关心ftf,会在每一次ftf后,自动处理
    // 源源不断向目的地写数据
    dma_circulation_enable(DMA1, DMA_CH0);
    // 12. 开启dma
    dma_channel_enable(DMA1, DMA_CH0);
}

void adc_multi_channel_dma_config(void)
{

    adc0_config();
    adc0_dma_config();
}

/**
 * 电压转电阻
 */
float adc_to_resistance(uint16_t adc_value)
{
    float Vntc = adc_value / 4096.0f * 3.3f;
    float Rntc = Vntc / ((3.3f - Vntc) / 10000);
    return Rntc;
}

int resistance_to_temperature(float rntc)
{
    int len = sizeof(temp_table) / sizeof(temp_table[0]);
    float min = ABS(temp_table[0] * 10 - rntc);
    float derta = 0;
    int Tntc = 0 - 55;
    for (int i = 1; i < len; i++)
    {
        derta = ABS(temp_table[i] * 10 - rntc);
        if (derta < min)
        {
            min = derta;
            Tntc = i - 55;
        }
    }

    return Tntc;
}

void adc_multi_channel_dma_test(void)
{
    adc_multi_channel_dma_config();
    while (1)
    {
        delay_1ms(1000);
        printf("热敏电阻:%d\n", adc_arr[0]);
        printf("热敏电阻温度:%d\n", resistance_to_temperature(adc_to_resistance(adc_arr[0])));
        printf("电位器:%d\n", adc_arr[1]);
        printf("内部温度:%d\n", adc_arr[2]);
    }
}
